#pragma once
#include "Pascal.h"

#include "wc3memory.h"
#include "wc3stringhash.h"

	//{ TArrayItemManager }

	//generic TArrayItemManager<TItem> = object
	//public
	//	procedure Initialize(out AItem: TItem); abstract;
	//	procedure Finalize(out AItem: TItem); abstract;
	//	procedure Copy(const ASource: TItem; out ADestination: TItem); abstract;
	//end;

class TDefaultArrayItemManager
{
public:
	static procedure Initialize(Pointer AItem, SizeUInt Size);
	static procedure Finalize(Pointer AItem, SizeUInt Size);
	static procedure Copy(Pointer ADestination, const Pointer ASource, SizeUInt Size);
};

#ifndef TArrayOfObjectsManager_H
#define TArrayOfObjectsManager_H
template <typename TItem>
class TArrayOfObjectsManager
{
public:
	static procedure Initialize(TItem *AItem, SizeUInt Size);
	static procedure Finalize(TItem *AItem, SizeUInt Size);
	static procedure Copy(TItem *ADestination, const TItem ASource, SizeUInt Size);
};
#endif

class TMissingArrayItemManager
{
public:
	static procedure Initialize(Pointer AItem, SizeUInt Size);
	static procedure Finalize(Pointer AItem, SizeUInt Size);
	static procedure Copy(Pointer ADestination, const Pointer ASource, SizeUInt Size);
};

#ifndef TSArrayM_H
#define TSArrayM_H
//template <typename T, typename TItemManager>
//class TArrayEnumerator_2;
//template <typename T, typename TItemManager>
//class TArrayItemPointers_2;
//template <typename T, typename TItemManager>
//class TArrayItemPointersEnumerator_2;
template <typename T, typename TItemManager>
class TSArrayM
{
public:
		typedef T* P;
		typedef TSArrayM* PSArray;

		class TArrayEnumerator;
		
		class TArrayItemPointers
		{
		public:
			typedef TArrayItemPointers* PArrayItemPointers;

			class TArrayItemPointersEnumerator;
		public:
			PSArray FOwner;
			P GetItem(Dword AIndex);
		public:
			//__declspec (property (get = GetItem)) P Items[];
		public:
			TArrayItemPointers(PSArray AOwner);
			TArrayItemPointersEnumerator GetEnumerator();
		};

		TArrayItemPointers* vTArrayItemPointers;
public:
		Dword FCapacity;
		Dword FLength;
		P FItems;
public:
		procedure SetLength(Dword ALength);
		procedure SetCapacity(Dword ACapacity);
		T GetItem(Dword AIndex);
		procedure SetItem(Dword AIndex, const T AValue);
		TArrayItemPointers GetItemPointers();
		Dword GetCapacity();
		Dword GetLength();
public:
		//__declspec (property (get = GetLength, put = SetLength)) Dword Length;
		//__declspec (property (get = GetCapacity, put = SetCapacity)) Dword Capacity;
		//__declspec (property (get = GetItem, put = SetItem)) T Items[];
		//__declspec (property (get = GetItemPointers)) TArrayItemPointers_2<T,TItemManager> ItemPointers;
//public:
		
//public:
		//Dword Length;//(FLength,procedure(*SetLength)(Dword ALength));
		//Dword Capacity;//(FCapacity,procedure(*SetCapacity)(Dword ACapacity));
		//T Items[];// read GetItem write SetItem;
		//TArrayItemPointers ItemPointers;// read GetItemPointers;
public:
		TSArrayM();
		~TSArrayM();
		Dword Add(T AValue);
		P GetNewItem();
		T Pop();
		TArrayEnumerator GetEnumerator();	
};
#endif

		template <typename T, typename TItemManager>
		class TSArrayM<T,TItemManager>::TArrayEnumerator : public TSArrayM<T,TItemManager>
		{
		private:
			PSArray FArray;
			Dword FCurrent;
		public:
			TArrayEnumerator(PSArray AArray);
			T GetCurrent();
			Boolean MoveNext();
			procedure Reset();
			//__declspec (property (get = GetCurrent)) T Current;
		};

		/*#ifndef TArrayEnumerator_2_H
		#define TArrayEnumerator_2_H
		template <typename T, typename TItemManager>
		class TArrayEnumerator_2 : public TSArrayM<T,TItemManager>::TArrayEnumerator {};
		#endif*/

		//#ifndef TArrayItemPointers_H
		//#define TArrayItemPointers_H
		/*template <typename T, typename TItemManager>
		class TSArrayM<T,TItemManager>::TArrayItemPointers : public TSArrayM<T,TItemManager>
		{
		public:
			typedef TArrayItemPointers* PArrayItemPointers;

			class TArrayItemPointersEnumerator;
		public:
			PSArray FOwner;
			P GetItem(Dword AIndex);
		public:
			//__declspec (property (get = GetItem)) P Items[];
		public:
			TArrayItemPointers(PSArray AOwner);
			TArrayItemPointersEnumerator GetEnumerator();
		};*/
		//#endif

		/*#ifndef TArrayItemPointers_2_H
		#define TArrayItemPointers_2_H
		template <typename T, typename TItemManager>
		class TArrayItemPointers_2 : public TSArrayM<T,TItemManager>::TArrayItemPointers {};
		#endif*/

			template <typename T, typename TItemManager>
			class TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator : public TSArrayM<T,TItemManager>::TArrayItemPointers
			{
			private:
				PSArray FOwner;
				Dword FCurrentIndex;
			public:
				TArrayItemPointersEnumerator(PSArray AOwner);
				P GetCurrent();
				Boolean MoveNext();
				procedure Reset();
				//__declspec (property (get = GetCurrent)) P Current;
			};

			//template <typename T, typename TItemManager>
			//class TArrayItemPointersEnumerator_2 : public TSArrayM<T,TItemManager>::TArrayItemPointers::TArrayItemPointersEnumerator {};
			

template<typename T> class TSArray : public TSArrayM<T, TDefaultArrayItemManager>{};

//#ifndef TSGrowableArrayM_H
//#define TSGrowableArrayM_H
template<typename T, typename TItemManager>
class TSGrowableArrayM : public TSArrayM<T, TItemManager>
{
public:
		Dword FGrowFactor;
public:
		TSGrowableArrayM();
		~TSGrowableArrayM();
};
//#endif
#ifndef TSGrowableArray_H
#define TSGrowableArray_H
template<typename T>
class TSGrowableArray : public TSGrowableArrayM<T, TDefaultArrayItemManager>
{
public:
		TSGrowableArray();
		~TSGrowableArray();
};
#endif
	// linked list
#ifndef TSLinkedNode_H
#define TSLinkedNode_H
template<typename P>
class TSLinkedNode
{
public:
		typedef TSLinkedNode* PNode;
public:
		PNode Previous;
		P Value;
public:
		Boolean IsLinked();
public:
		//__declspec (property (get = IsLinked)) Boolean Linked;
public:
		procedure Clear();
		procedure Lock();
};
#endif

class TMissingInitialOffset
{
public:
		static SizeUInt GetValue();
};

#ifndef TSLinkedList_H
#define TSLinkedList_H
//template<typename T, typename TInitialOffset>
//class PNode_2;
template<typename T, typename TInitialOffset>
class TLinkedListEnumerator_2;
template <typename T, typename TInitialOffset>
class TLinkedListReversedEnumerator_2;
template<typename T, typename TInitialOffset>
class TSLinkedList
{
public:
		typedef T* P;
		typedef TSLinkedList* PSLinkedList;
		typedef TSLinkedNode<P> TNode;
		typedef TNode* PNode;

		class TLinkedListEnumerator;

		class TLinkedListReversedEnumerator;

		//TLinkedListEnumerator vTLinkedListEnumerator;
		//TLinkedListReversedEnumerator vTLinkedListReversedEnumerator;

public:
		Dword FOffset;
		TNode FRoot;
public:
		Integer GetLength();
		PNode GetNodeOfItem(P AItem);
		P GetItemOfNode(PNode ANode);
		PNode GetNextNode(PNode ANode);
		procedure UnlinkNode(PNode ANode);
		procedure InsertValueAfter(PNode ANode, P AValue);
		procedure LinkNodes(PNode ANodeA, PNode ANodeB);
		P GetFirst();
		P GetLast();
public:
		//__declspec (property (get = GetLength)) Integer Length;
		//__declspec (property (get = GetFirst)) P First;
		//__declspec (property (get = GetLast)) P Last;
public:
		TSLinkedList();
		~TSLinkedList();
		procedure Add(P AItem);
		procedure Prepend(P AItem);
		procedure Remove(P AItem);
		procedure Clear();
		P GetNextItem(P AItem);
		TLinkedListEnumerator_2<T,TInitialOffset> GetEnumerator();
		TLinkedListReversedEnumerator_2<T,TInitialOffset> GetReversedEnumerator();
};
#endif

		//template<typename T, typename TInitialOffset>
		//class PNode_2 : public TSLinkedList<T,TInitialOffset>::PNode {};

		template<typename T, typename TInitialOffset>
		class TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator : public TSLinkedList<T,TInitialOffset>
		{
		private:
			PSLinkedList FList;
			P FCurrent;
			PNode FCurrentNode;
		public:
			TLinkedListEnumerator(PSLinkedList AList);
			TLinkedListEnumerator_2<T,TInitialOffset> GetEnumerator();
			P GetCurrent();
			Boolean MoveNext();
			procedure Reset();
			//__declspec (property (get = GetCurrent)) P Current;
		};

		template<typename T, typename TInitialOffset>
		class TLinkedListEnumerator_2 : public TSLinkedList<T,TInitialOffset>::TLinkedListEnumerator {};

		template<typename T, typename TInitialOffset>
		class TSLinkedList<T,TInitialOffset>::TLinkedListReversedEnumerator : public TSLinkedList<T,TInitialOffset>
		{
		private:
			PSLinkedList FList;
			P FCurrent;
			PNode FCurrentNode;
		public:
			TLinkedListReversedEnumerator(PSLinkedList AList);
			P GetCurrent();
			Boolean MoveNext();
			procedure Reset();
			//__declspec (property (get = GetCurrent)) P Current;
		};

		template <typename T, typename TInitialOffset>
		class TLinkedListReversedEnumerator_2 : public TSLinkedList<T,TInitialOffset>::TLinkedListReversedEnumerator {};

	// dictionary

	//{ TKeyAsHashManager }

class THashlessKeyManager
{
public:
		static Dword GetKeyHash(const Pointer AKey);
		static Boolean IsKeysEqual(const Pointer KeyA, const Pointer KeyB);
		static procedure CopyKey(Pointer Destination, const Pointer Source);
		static procedure ClearKey(Pointer AKey);
};

	class GPTrue
	{
		public:
			static Boolean GetValue();
	};

	class GPFalse
	{
		public:
		static Boolean GetValue();
	};

template <typename TCloneKey, typename TCaseSensetive>
class TStringHashKeyManagerBase
{
public:
		static Dword GetKeyHash(const PChar AKey);
		static Boolean IsKeysEqual(const PChar KeyA, const PChar KeyB);
		static procedure CopyKey(PChar &Destination, const PChar Source);
		static procedure ClearKey(PChar &AKey);
};

class TStringHashKeyManager : public TStringHashKeyManagerBase<GPTrue, GPTrue>{};
class TCaseInsensetiveStringHashKeyManager : public TStringHashKeyManagerBase<GPTrue, GPFalse>{};
class TConstantStringHashKeyManager : public TStringHashKeyManagerBase<GPFalse, GPTrue>{};

template <typename TKey>
class THashKeyData
{
public:
		typedef THashKeyData* PHashKeyData;
		typedef TSLinkedNode<PHashKeyData> PageNode_and_ItemsNode_Type;
public:
		Dword Hash;
		PageNode_and_ItemsNode_Type PageNode, ItemsNode;
		TKey Key;
};

template <typename TKey>
class TSHashObject
{
public:
	typedef THashKeyData<TKey> HashKeyData_Type_2;
public:
		HashKeyData_Type_2 HashKeyData;
};

template <typename TKey, typename TValue>
class TSHashNode : public TSHashObject<TKey>
{
public:
		TValue Value;
};

class TSHashTable_VMT
{
public:
		typedef procedure (__stdcall *pDeleteItem_1) (Pointer Item);
		typedef Pointer (__stdcall *pCreateItem_1) (Pointer List, SizeUInt ExtraSize, Dword ExtraFlags);
		typedef procedure (__stdcall *pDelete_1) (Boolean FreeMemory);
		typedef procedure (__stdcall *pClear_1) ();

		pDeleteItem_1 pDeleteItem;
		pCreateItem_1 pCreateItem;
		pDelete_1 pDelete;
		pClear_1 pClear;
public:
		Pointer CreateItem(Pointer this_1, Pointer List, SizeUInt ExtraSize, Dword ExtraFlags);
		procedure DeleteItem(Pointer this_1, Pointer Item);
};

typedef TSHashTable_VMT* PSHashTable_VMT;

#ifndef TSHashTable_H
#define TSHashTable_H
template <typename TKey, typename TValue, typename TKeyManager>
class TItems_TLinkedListReversedEnumerator;
template <typename TKey, typename TValue, typename TKeyManager>
class TSHashTable
{
private:
		static const Dword PAGE_LIMIT = 12;
		static const Dword MAX_PAGES_COUNT = 8192;
		static const Dword INITIAL_PAGES_COUNT = 4;
public:
		class TItemsNodeOffset
		{
		public:
			static SizeUInt GetValue();
		};

		class TPageNodeOffset
		{
		public:
			static SizeUInt GetValue();
		};
		
		typedef TValue* PValue;

		typedef TSLinkedList<TValue, TItemsNodeOffset> TItems;
		typedef TItems* PItems;

		typedef TSLinkedList<TValue, TPageNodeOffset> TPage;
		typedef TPage* PPage;

		typedef TArrayOfObjectsManager<TPage> TPageManager;
		typedef TSGrowableArrayM<TPage, TPageManager> TPages;
public:
		Pointer vtable;
		TItems Items;
		Dword Counter;
		TPages Pages;
		Dword HashMask;
public:
		procedure InitPages();
		procedure Grow();
		procedure SetPagesCount(Dword ACount);
		procedure Put(PValue AValue);
public:
		Boolean Find(const TKey AKey, Dword AHash, TValue* &AValue);
		PValue Get(const TKey AKey, Dword AHash);
		Boolean Find(const TKey AKey, TValue* &AValue);
		PValue Get(const TKey AKey);
		procedure Put(const TKey AKey, PValue AValue);
		procedure FastPut(const TKey AKey, Dword AHash, PValue AValue);
		Boolean Remove(const TKey AKey);
		procedure Clear();
		PValue CreateItem(const TKey AKey);
		TItems_TLinkedListReversedEnumerator<TKey,TValue,TKeyManager> GetEnumerator();
		TSHashTable();
		~TSHashTable();
public:
		//__declspec (property (get = Get)) PValue ItemsByKey[];
};
#endif

/*template <typename TKey, typename TValue, typename TKeyManager>
class TSHashTable<TKey,TValue,TKeyManager>::TItemsNodeOffset : public TSHashTable<TKey,TValue,TKeyManager>
{
public:
	static SizeUInt GetValue();
};*/

template <typename TKey, typename TValue, typename TKeyManager>
class TItems_TLinkedListReversedEnumerator : public TLinkedListReversedEnumerator_2<TValue,TSHashTable<TKey,TValue,TKeyManager>::template TItemsNodeOffset> {};